this.notify(this._notification);
},
- createNotificationIcon: function() {
+ createIcon: function(size) {
return new St.Icon({ gicon: this.mount.get_icon(),
- icon_size: this.ICON_SIZE });
+ icon_size: size });
}
});
// the content area (as with addBody()).
//
// By default, the icon shown is created by calling
-// source.createNotificationIcon(). However, if @params contains an 'icon'
+// source.createIcon(). However, if @params contains an 'icon'
// parameter, the passed in icon will be used.
//
// If @params contains a 'titleMarkup', 'bannerMarkup', or
this._table.remove_style_class_name('multi-line-notification');
if (!this._icon) {
- this._icon = params.icon || this.source.createNotificationIcon();
+ this._icon = params.icon || this.source.createIcon(this.source.ICON_SIZE);
this._table.add(this._icon, { row: 0,
col: 0,
x_expand: false,
});
Signals.addSignalMethods(Notification.prototype);
-const Source = new Lang.Class({
- Name: 'MessageTraySource',
+const SourceActor = new Lang.Class({
+ Name: 'SourceActor',
- ICON_SIZE: 24,
-
- _init: function(title, iconName, iconType) {
- this.title = title;
- this.iconName = iconName;
- this.iconType = iconType;
+ _init: function(source, size) {
+ this._source = source;
this.actor = new Shell.GenericContainer();
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
this.actor.connect('allocate', Lang.bind(this, this._allocate));
- this.actor.connect('destroy', Lang.bind(this,
- function() {
- this._actorDestroyed = true;
- }));
+ this.actor.connect('destroy', Lang.bind(this, function() {
+ this._actorDestroyed = true;
+ }));
this._actorDestroyed = false;
this._counterLabel = new St.Label();
child: this._counterLabel });
this._counterBin.hide();
- this._iconBin = new St.Bin({ width: this.ICON_SIZE,
- height: this.ICON_SIZE,
+ this._iconBin = new St.Bin({ width: size,
+ height: size,
x_fill: true,
y_fill: true });
this.actor.add_actor(this._iconBin);
this.actor.add_actor(this._counterBin);
- this.isTransient = false;
- this.isChat = false;
- this.isMuted = false;
-
- this.notifications = [];
+ this._source.connect('count-changed', Lang.bind(this, this._updateCount));
+ this._updateCount();
+ },
- this._setSummaryIcon(this.createNotificationIcon());
+ setIcon: function(icon) {
+ this._iconBin.child = icon;
},
_getPreferredWidth: function (actor, forHeight, alloc) {
this._counterBin.allocate(childBox, flags);
},
+ _updateCount: function() {
+ if (this._actorDestroyed)
+ return;
+
+ this._counterBin.visible = this._source.countVisible;
+ this._counterLabel.set_text(this._source.count.toString());
+ },
+});
+
+const Source = new Lang.Class({
+ Name: 'MessageTraySource',
+
+ ICON_SIZE: 24,
+
+ _init: function(title, iconName, iconType) {
+ this.title = title;
+ this.iconName = iconName;
+ this.iconType = iconType;
+
+ this.count = 0;
+
+ this.isTransient = false;
+ this.isChat = false;
+ this.isMuted = false;
+
+ this.notifications = [];
+
+ this.mainIcon = new SourceActor(this, this.ICON_SIZE);
+ this._setSummaryIcon(this.createIcon(this.ICON_SIZE));
+ },
+
_setCount: function(count, visible) {
if (isNaN(parseInt(count)))
throw new Error("Invalid notification count: " + count);
- if (this._actorDestroyed)
- return;
-
- this._counterBin.visible = visible;
- this._counterLabel.set_text(count.toString());
+ this.count = count;
+ this.countVisible = visible;
+ this.emit('count-changed');
},
_updateCount: function() {
this.emit('muted-changed');
},
- // Called to create a new icon actor (of size this.ICON_SIZE).
+ // Called to create a new icon actor.
// Provides a sane default implementation, override if you need
// something more fancy.
- createNotificationIcon: function() {
+ createIcon: function(size) {
return new St.Icon({ icon_name: this.iconName,
icon_type: this.iconType,
- icon_size: this.ICON_SIZE });
+ icon_size: size });
},
- // Unlike createNotificationIcon, this always returns the same actor;
+ // Unlike createIcon, this always returns the same actor;
// there is only one summary icon actor for a Source.
getSummaryIcon: function() {
- return this.actor;
+ return this.mainIcon.actor;
},
pushNotification: function(notification) {
//// Protected methods ////
_setSummaryIcon: function(icon) {
- if (this._iconBin.child)
- this._iconBin.child.destroy();
- this._iconBin.child = icon;
+ this.mainIcon.setIcon(icon);
},
open: function(notification) {
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
+const GdkPixbuf = imports.gi.GdkPixbuf;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Lang = imports.lang;
Lang.bind(this, this._onFocusAppChanged));
},
- _iconForNotificationData: function(icon, hints, size) {
- let textureCache = St.TextureCache.get_default();
-
+ _iconForNotificationData: function(icon, hints) {
// If an icon is not specified, we use 'image-data' or 'image-path' hint for an icon
// and don't show a large image. There are currently many applications that use
// notify_notification_set_icon_from_pixbuf() from libnotify, which in turn sets
// a large image.
if (icon) {
if (icon.substr(0, 7) == 'file://')
- return textureCache.load_uri_async(icon, size, size);
+ return new Gio.FileIcon({ file: Gio.File.new_for_uri(icon) });
else if (icon[0] == '/') {
- let uri = GLib.filename_to_uri(icon, null);
- return textureCache.load_uri_async(uri, size, size);
+ return new Gio.FileIcon({ file: Gio.File.new_for_path(icon) });
} else
- return new St.Icon({ icon_name: icon,
- icon_type: St.IconType.FULLCOLOR,
- icon_size: size });
+ return new Gio.ThemedIcon({ name: icon });
} else if (hints['image-data']) {
let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels, data] = hints['image-data'];
- return textureCache.load_from_raw(data, hasAlpha, width, height, rowStride, size);
+ return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
+ bitsPerSample, width, height, rowStride);
} else if (hints['image-path']) {
- return textureCache.load_uri_async(GLib.filename_to_uri(hints['image-path'], null), size, size);
+ return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) });
} else {
let stockIcon;
switch (hints.urgency) {
stockIcon = 'gtk-dialog-error';
break;
}
- return new St.Icon({ icon_name: stockIcon,
- icon_type: St.IconType.FULLCOLOR,
- icon_size: size });
+ return new Gio.ThemedIcon({ name: stockIcon });
}
},
[ndata.id, ndata.icon, ndata.summary, ndata.body,
ndata.actions, ndata.hints, ndata.notification];
- let iconActor = this._iconForNotificationData(icon, hints, source.ICON_SIZE);
+ let gicon = this._iconForNotificationData(icon, hints);
+ let iconActor = new St.Icon({ gicon: gicon,
+ icon_type: St.IconType.FULLCOLOR,
+ icon_size: source.ICON_SIZE });
if (notification == null) {
notification = new MessageTray.Notification(source, summary, body,
// of the 'transient' hint with hints['transient'] rather than hints.transient
notification.setTransient(hints['transient'] == true);
- let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
- source.processNotification(notification, sourceIconActor);
+ let sourceGIcon = source.useNotificationIcon ? this._iconForNotificationData(icon, hints) : null;
+ source.processNotification(notification, sourceGIcon);
},
CloseNotification: function(id) {
this.destroy();
},
- processNotification: function(notification, icon) {
- if (!this.app)
- this._setApp();
- if (!this.app && icon)
- this._setSummaryIcon(icon);
+ processNotification: function(notification, gicon) {
+ if (gicon)
+ this._gicon = gicon;
+ this._setSummaryIcon(this.createIcon(this.ICON_SIZE));
let tracker = Shell.WindowTracker.get_default();
if (notification.resident && this.app && tracker.focus_app == this.app)
// notification-based icons (ie, not a trayicon) or if it was unset before
if (!this.trayIcon) {
this.useNotificationIcon = false;
- this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
+ this._setSummaryIcon(this.createIcon(this.ICON_SIZE));
}
},
this.parent();
},
- createNotificationIcon: function() {
- // We set the summary icon ourselves.
- return null;
+ createIcon: function(size) {
+ if (this.trayIcon) {
+ return new Clutter.Clone({ width: size,
+ height: size,
+ source: this.trayIcon });
+ } else if (this.app) {
+ return this.app.create_icon_texture(size);
+ } else if (this._gicon) {
+ return new St.Icon({ gicon: this._gicon,
+ icon_size: size });
+ } else {
+ return null;
+ }
}
});
this._notification.appendAliasChange(oldAlias, newAlias);
},
- createNotificationIcon: function() {
+ createIcon: function(size) {
this._iconBox = new St.Bin({ style_class: 'avatar-box' });
- this._iconBox._size = this.ICON_SIZE;
+ this._iconBox._size = size;
let textureCache = St.TextureCache.get_default();
let file = this._contact.get_avatar_file();
},
_updateAvatarIcon: function() {
- this._setSummaryIcon(this.createNotificationIcon());
- this._notification.update(this._notification.title, null, { customContent: true, icon: this.createNotificationIcon() });
+ this._setSummaryIcon(this.createIcon(this.ICON_SIZE));
+ this._notification.update(this._notification.title, null, { customContent: true });
},
open: function(notification) {
this.parent();
},
- createNotificationIcon: function() {
+ createIcon: function(size) {
return new St.Icon({ gicon: this._gicon,
- icon_size: this.ICON_SIZE });
+ icon_size: size });
}
});
this.signalIDs = [];
},
- createNotificationIcon : function() {
- return this._app.create_icon_texture(this.ICON_SIZE);
+ createIcon : function(size) {
+ return this._app.create_icon_texture(size);
},
open : function(notification) {
#include "shell-util.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
#ifdef HAVE__NL_TIME_FIRST_WEEKDAY
#include <langinfo.h>
return ret;
}
+
+/**
+ * shell_util_create_pixbuf_from_data:
+ * @data: (array length=len) (element-type guint8) (transfer full):
+ * @len:
+ * @colorspace:
+ * @has_alpha:
+ * @bits_per_sample:
+ * @width:
+ * @height:
+ * @rowstride:
+ *
+ * Workaround for non-introspectability of gdk_pixbuf_from_data().
+ *
+ * Returns: (transfer full):
+ */
+GdkPixbuf *
+shell_util_create_pixbuf_from_data (const guchar *data,
+ gsize len,
+ GdkColorspace colorspace,
+ gboolean has_alpha,
+ int bits_per_sample,
+ int width,
+ int height,
+ int rowstride)
+{
+ return gdk_pixbuf_new_from_data (data, colorspace, has_alpha,
+ bits_per_sample, width, height, rowstride,
+ (GdkPixbufDestroyNotify) g_free, NULL);
+}
#include <gio/gio.h>
#include <clutter/clutter.h>
#include <libsoup/soup.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
G_BEGIN_DECLS
gboolean shell_util_wifexited (int status,
int *exit);
+GdkPixbuf *shell_util_create_pixbuf_from_data (const guchar *data,
+ gsize len,
+ GdkColorspace colorspace,
+ gboolean has_alpha,
+ int bits_per_sample,
+ int width,
+ int height,
+ int rowstride);
G_END_DECLS